package com.cellulam.framework.fs.excel.utils;

import com.google.common.collect.Maps;
import com.cellulam.framework.core.utils.LocalDateUtils;
import com.cellulam.framework.fs.excel.annotion.ExcelColumn;
import com.cellulam.framework.fs.excel.annotion.ExcelIgnore;
import com.cellulam.framework.fs.excel.model.ExcelFieldMeta;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 *
 */
public abstract class ExcelMetaUtils {

    private static final Logger logger = LoggerFactory.getLogger(ExcelMetaUtils.class);

    private static final Map<Class<?>, List<ExcelFieldMeta>> cache = Maps.newHashMap();

    private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 读取类中的excel的元数据
     *
     * @param beanClass
     * @return
     */
    public static List<ExcelFieldMeta> readExcelProperty(Class<?> beanClass) {
        List<ExcelFieldMeta> excelItems = cache.get(beanClass);

        if (excelItems != null) {
            return excelItems;
        }

        excelItems = new ArrayList<>();

        Field[] fields = beanClass.getDeclaredFields();
        int colIndex = 0;
        for (Field field : fields) {
            ExcelColumn anno = field.getAnnotation(ExcelColumn.class);
            if (anno == null) {
                continue;
            }

            if (field.getAnnotation(ExcelIgnore.class) != null) {
                continue;
            }

            int index = colIndex++;

            ExcelFieldMeta exField = new ExcelFieldMeta();
            exField.setName(field.getName());
            exField.setTitle(anno.value());
            exField.setPattern(anno.pattern());

            if (anno.index() > -1) {
                exField.setIndex(anno.index());
            } else {
                exField.setIndex(index);
            }

            field.setAccessible(true);
            exField.setRawField(field);

            excelItems.add(exField);
        }

        excelItems.sort(Comparator.comparingInt(ExcelFieldMeta::getIndex));

        return excelItems;
    }


    /**
     * 获取字段值
     *
     * @param field
     * @param cell
     * @return
     */
    public static Object getFieldValue(ExcelFieldMeta field, Cell cell) {
        Class<?> fieldType = field.getRawField().getType();
        String fieldStrValue = CellUtils.getFieldStrValue(cell);
        if (Integer.class.equals(fieldType)) {
            return parseInt(fieldStrValue, null);
        }
        if (Integer.TYPE.equals(fieldType)) {
            return parseInt(fieldStrValue, 0);
        }
        if (Boolean.class.equals(fieldType)) {
            return parseBoolean(fieldStrValue, null);
        }
        if (Boolean.TYPE.equals(fieldType)) {
            return parseBoolean(fieldStrValue, false);
        }
        if (Short.class.equals(fieldType)) {
            return parseShort(fieldStrValue, null);
        }
        if (Short.TYPE.equals(fieldType)) {
            return parseShort(fieldStrValue, (short) 0);
        }
        if (Long.class.equals(fieldType)) {
            return parseLong(fieldStrValue, null);
        }
        if (Long.TYPE.equals(fieldType)) {
            return parseLong(fieldStrValue, 0L);
        }
        if (Float.class.equals(fieldType)) {
            return parseFloat(fieldStrValue, null);
        }
        if (Float.TYPE.equals(fieldType)) {
            return parseFloat(fieldStrValue, 0F);
        }
        if (Double.class.equals(fieldType)) {
            return parseDouble(fieldStrValue, null);
        }
        if (Double.TYPE.equals(fieldType)) {
            return parseDouble(fieldStrValue, 0D);
        }
        if (String.class.equals(fieldType)) {
            return fieldStrValue;
        }
        if (Date.class.equals(fieldType)) {
            if (fieldStrValue == null || fieldStrValue.isEmpty()) {
                return null;
            }
            return parseDate(fieldStrValue, field.getPattern(), null);
        }
        if (LocalDateTime.class.equals(fieldType)) {
            if (fieldStrValue == null || fieldStrValue.isEmpty()) {
                return null;
            }
            return parseLocalDateTime(fieldStrValue, field.getPattern(), null);
        }
        if (LocalDate.class.equals(fieldType)) {
            if (fieldStrValue == null || fieldStrValue.isEmpty()) {
                return null;
            }
            return parseLocalDate(fieldStrValue, field.getPattern(), null);
        }
        throw new RuntimeException(String.format("illegal type: %s", fieldType));
    }


    /**
     * 转换为Localdate
     *
     * @param text
     * @param pattern
     * @param defaultValue
     * @return
     */
    private static LocalDate parseLocalDate(String text, String pattern, LocalDate defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        if (StringUtils.isBlank(pattern)) {
            return LocalDate.parse(text);
        }
        try {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDate.parse(text, dateTimeFormatter);
        } catch (Exception e) {
            logger.error("parse local-date error", e);
            return defaultValue;
        }
    }

    /**
     * 转换为LocaldateTime
     *
     * @param text
     * @param pattern
     * @param defaultValue
     * @return
     */
    private static LocalDateTime parseLocalDateTime(String text, String pattern, LocalDateTime defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        if (StringUtils.isBlank(pattern)) {
            return LocalDateTime.parse(text, DEFAULT_DATETIME_FORMATTER);
        }
        try {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDateTime.parse(text, dateTimeFormatter);
        } catch (Exception e) {
            logger.error("parse local-date-time error", e);
            return defaultValue;
        }
    }

    /**
     * 转换Date
     *
     * @param text
     * @param pattern
     * @param defaultValue
     * @return
     */
    private static Date parseDate(String text, String pattern, Date defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        if (StringUtils.isBlank(pattern)) {
            LocalDateTime ldt = LocalDateTime.parse(text);
            return LocalDateUtils.convertToDate(ldt);
        }
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
            return simpleDateFormat.parse(text);
        } catch (ParseException e) {
            logger.error("parse date error", e);
            return defaultValue;
        }
    }

    /**
     * 转换成short
     *
     * @param text
     * @param defaultValue
     * @return
     */
    private static Short parseShort(String text, Short defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        try {
            return Double.valueOf(text).shortValue();
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 转成成long
     *
     * @param text
     * @param defaultValue
     * @return
     */
    private static Long parseLong(String text, Long defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        try {
            return Double.valueOf(text).longValue();
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 转换float
     *
     * @param text
     * @param defaultValue
     * @return
     */
    public static Float parseFloat(String text, Float defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        try {
            return Double.valueOf(text).floatValue();
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 转换double
     *
     * @param text
     * @param defaultValue
     * @return
     */
    public static Double parseDouble(String text, Double defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        try {
            return Double.valueOf(text);
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    /**
     * 转换成boolean
     *
     * @param text
     * @param defaultValue
     * @return
     */
    private static Boolean parseBoolean(String text, Boolean defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        if (Boolean.TRUE.toString().equalsIgnoreCase(text)) {
            return true;
        } else if (Boolean.FALSE.toString().equalsIgnoreCase(text)) {
            return false;
        } else {
            return defaultValue;
        }
    }


    /**
     * 转换int
     *
     * @param text
     * @param defaultValue
     * @return
     */
    private static Integer parseInt(String text, Integer defaultValue) {
        if (text == null || text.isEmpty()) {
            return defaultValue;
        }
        try {
            return Double.valueOf(text).intValue();
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }


}
